﻿using NModbus;
using Sunny.UI;
using System;
using System.Linq;
using System.Net.Sockets;
using System.Windows.Forms;

namespace MyModbusTCPDemo
{
    public partial class Form1 : UIForm
    {
        #region 属性定义
        private TcpClient client;
        private IModbusMaster master;
        private IModbusFactory factory;
        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        #region 按钮触发的方法
        private void Btn_Con_Click(object sender, System.EventArgs e)
        {
            if (client != null && client.Client != null && client.Connected)
            {
                UIMessageBox.Show("ModbusTCP已连接，请不要重复点击");
                return;
            }
            client = new TcpClient();
            factory = new ModbusFactory();
            string ip = TxtBox_Ip.Text;
            try
            {
                int port = int.Parse(TxtBox_Port.Text);
                client.Connect(ip, port);
                master = factory.CreateMaster(client);
            }
            catch (Exception ex)
            {
                UIMessageBox.Show($"出现异常了：{ex.Message}");
            }
            if (!client.Connected)
            {
                UIMessageBox.Show("ModbusTCP连接失败");
                return;
            }
            UIMessageBox.Show("ModbusTCP连接成功");
        }

        private void Btn_DisCon_Click(object sender, System.EventArgs e)
        {
            try
            {
                VerifyConnected();
                client.Dispose();
                client.Close();
                master.Dispose();
                UIMessageBox.Show("ModbusTCP关闭连接成功");
            }
            catch (Exception ex)
            {
                UIMessageBox.Show($"出现异常：{ex.Message}");
            }
        }

        private void Btn_Read_Click(object sender, EventArgs e)
        {
            try
            {
                VerifyConnected();
                byte slaveAddress = byte.Parse(TxtBox_SlaveAddr.Text);
                ushort startAddress = ushort.Parse(TxtBox_StartAddr.Text);
                ushort numberOfPoints = ushort.Parse(TxtBox_ReadNum.Text);
                bool[] res = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
                TxtBox_Val.Text = string.Join(",", res);
            }
            catch (Exception ex)
            {
                UIMessageBox.Show($"出现异常：{ex.Message}");
            }
        }

        private void Btn_Write_Click(object sender, EventArgs e)
        {
            try
            {
                VerifyConnected();
                string type = ComBox_Type.Text;
                switch (type)
                {
                    case "线圈":
                        WriteCoil();
                        break;
                    case "寄存器":
                        WriteRegister();
                        break;
                    default:
                        throw new Exception("请选择合适的类型下拉框");
                }
                UIMessageBox.Show("写入成功");
            }
            catch (Exception ex)
            {
                UIMessageBox.Show($"出现异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 写入寄存器
        /// </summary>
        private void WriteRegister()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 写入线圈
        /// </summary>
        private void WriteCoil()
        {
            string val = TxtBox_Val.Text;
            byte slaveAddress = byte.Parse(TxtBox_SlaveAddr.Text);
            ushort startAddress = ushort.Parse(TxtBox_StartAddr.Text);
            val = val.Replace(" ", "").Trim(','); // 去掉所有空白字符，并去掉左右两边的逗号
            int commaCount = val.Count(c => c == ','); // 判断逗号数量
            try
            {
                if (commaCount == 0)
                {
                    // 写入单个线圈
                    bool valBool = bool.Parse(val);
                    master.WriteSingleCoilAsync(slaveAddress, startAddress, valBool);
                    return;
                }
                // 写入多个线圈
                bool[] bools = val.Split(',')
                      .Select(bool.Parse)
                      .ToArray();
                bool[] toWrite = bools;
                int writeNum = int.Parse(TxtBox_ReadNum.Text);
                if (writeNum < bools.Length)
                {
                    toWrite = bools.Take(writeNum).ToArray();
                }
                master.WriteMultipleCoilsAsync(slaveAddress, startAddress, toWrite);
            }
            catch (Exception ex)
            {
                throw new Exception($"写入失败：{ex.Message}");
            }
        }
        #endregion

        /// <summary>
        /// 验证当前是否连接，如果未连接，则抛出异常
        /// </summary>
        /// <exception cref="Exception"></exception>
        private void VerifyConnected()
        {
            if (client == null || client.Client == null || !client.Connected)
            {
                throw new Exception("ModbusTCP未连接");
            }
        }
    }
}
